package cn.texous.demo.dgs.client;

import cn.texous.demo.dgs.config.OauthProperties;
import cn.texous.demo.dgs.model.resp.CheckTokenResp;
import cn.texous.demo.dgs.util.ServerHttpRequestUtils;
import cn.texous.util.commons.constant.Result;
import cn.texous.util.commons.util.AuthorizationUtils;
import cn.texous.util.commons.util.GsonUtils;
import cn.texous.util.commons.util.MessageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 * insert description here
 *
 * @author Showa.L
 * @since 2019/7/14 10:11
 */
@Slf4j
@Component
public class AuthorClient {

    @Autowired
    private OauthProperties oauthProperties;

    /**
     * 登录操作
     *
     * @param request 请求
     * @return
     */
    public Mono<ClientResponse> login(ServerHttpRequest request) {
        WebClient webClient = WebClient.create(oauthProperties.getTokenUri());
        Map<String, String> params = changeMap(request.getQueryParams());
        params.put("grant_type", "password");
        String uri = getUri(oauthProperties.getTokenUri(), params);

        return webClient.post().uri(uri).contentType(MediaType.APPLICATION_JSON_UTF8).exchange();

    }

    /**
     * 请求路径鉴权
     *
     * @param request 请求
     * @return
     */
    public Result authUri(ServerHttpRequest request) {
        Map<String, String> params = new HashMap<>();
        params.put("access_token", ServerHttpRequestUtils.getAccessToken(request));
        params.put("path", request.getQueryParams().getFirst("path"));
        String uri = getUri(oauthProperties.getCheckAuthUri(), params);
        String url = String.format("%s%s", oauthProperties.getBaseUrl(), uri);
        MessageUtil.HttpsRequestParam param = MessageUtil.HttpsRequestParam.builder()
                .requestMethod("POST")
                .requestUrl(url)
                .build();
        String respStr = MessageUtil.commonRequest(param);
        log.info("权限校验结果：{}", respStr);
        return Result.ok(respStr);
    }

    /**
     * 校验 accesstoken
     *
     * @param accessToken accesstoken
     * @return
     */
    public boolean effectiveAccessToken(String accessToken) {
        Map<String, String> params = new HashMap<>();
        params.put("token", accessToken);
        String uri = getUri(oauthProperties.getCheckTokenUri(), params);
        String url = String.format("%s%s", oauthProperties.getBaseUrl(), uri);
        MessageUtil.HttpsRequestParam param = MessageUtil.HttpsRequestParam.builder()
                .header(getAuthorizationHeader())
                .requestMethod("POST")
                .requestUrl(url)
                .build();
        String respStr = MessageUtil.commonRequest(param);
        log.info("校验 access_token: {}, 结果: {}", accessToken, respStr);
        CheckTokenResp resp = GsonUtils.fromJson(respStr, CheckTokenResp.class);
        return resp != null && resp.isActive();
    }

    private Map<String, String> getAuthorizationHeader() {
        String basic = AuthorizationUtils.getAuthorizationStr(
                oauthProperties.getClientId(), oauthProperties.getClientSecret());
        Map<String, String> header = new HashMap<>();
        header.put("Authorization", "Basic " + basic);
        return header;
    }

    private Map<String, String> changeMap(MultiValueMap<String, String> queryParams) {
        Map<String, String> result = new HashMap<>();
        if (queryParams == null)
            return result;
        Optional.of(queryParams)
                .map(Map::entrySet)
                .ifPresent(p ->
                        p.forEach(item -> {
                            result.put(item.getKey(), String.join(",", item.getValue()));
                        }));
        return result;
    }

    /**
     * 拼接请求链接
     *
     * @param uri uri
     * @param params params
     * @return
     */
    private String getUri(String uri, Map<String, String> params) {
        if (CollectionUtils.isEmpty(params))
            return uri;
        StringBuilder sb = new StringBuilder(uri);
        sb.append("?");
        Set<Map.Entry<String, String>> entrySet = params.entrySet();
        for (Map.Entry<String, String> entry : entrySet) {
            sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        sb.deleteCharAt(sb.lastIndexOf("&"));
        return sb.toString();
    }
}
